const express = require('express');

const random = require( '../utils/random' );
const encryptor = require( '../utils/encrypt' );
const Customer = require( '../models/customer' );
const tokenHelper = require( '../utils/token');

const router = express.Router();

// 用户注册
router.post( '/customer/sign/up' , async (req,resp,next)=>{
    // 第一个中间件用来实现数据校验
    let { username , password } = req.body ;

    // 对 username 和 password 进行检查

    // 根据登录名称查询用户
    let customer = await Customer.findOne( { where: { username } } );
    // 判断用户是否存在
    if( customer ) {
        resp.json( { success: false , message: '登录名称被占用' } );
        return ;
    }
    next(); // 当数据通过校验时就调用下一个中间件
},(req,resp)=>{
    // 从请求中获取参数
    let { username , password , nickname } = req.body ;
    // 获取发布者的IP地址
    let ip = req.ip;
    // 随机产生盐值
    let salt = random.salt();
    // 对密码加盐并加密
    password = encryptor.encrypt( password , salt )
    // 采用对象字面量创建对象
    let instance = { 
        id: random.id() ,
        username,
        nickname,
        salt,
        password,
        signUpTime: new Date(),
        signUpIp: ip,
    };
    // 将用户信息保存到数据库中
    Customer.create( instance )
            .then( result => {
                console.log( result.toJSON() );
                resp.json( { success: true , message: '注册成功' } );
            }).catch( error => {
                console.log( error );
                resp.json( { success: false , message: '注册失败' } );
            });
});

// 用户登录
router.post( '/customer/sign/in' , (req,resp,next)=>{
    // 第一个中间件用来实现数据校验
    let { username , password } = req.body ;
    // 对 username 和 password 进行检查

    next(); // 当数据通过校验时就调用下一个中间件
}, async (req,resp)=>{
    let { username , password } = req.body ;
    const customer = await Customer.findOne({ 
        attributes:['id','username','password','salt','nickname'], 
        where: { username } 
    });

    if( customer ) {
        // 根据数据库中保存的盐值对用户在页面输入的密码进行加密
        password = encryptor.encrypt( password , customer.salt );
        // 如果用户输入的密码在加盐加密后与数据库中保存的密码不相同
        if( customer.password != password ){
            resp.json( { success: false, message: '登录密码错误' } );
            return ;
        }
        /* - - - 当登录名称和登录密码都正确时才执行下列操作 - - - */
        const instance = { 
            id: customer.id , 
            username: customer.username , 
            nickname: customer.nickname 
        };
        // 创建 token 并指定其认证方式为 Bearer
        const token = tokenHelper.generate( instance );
        // 将token返回给客户端
        resp.json( { success: true , message: '登录成功' , token: token } );
        return;
    }
    resp.json( { success: false, message: '登录名称错误' } );
});

// 获取用户信息
router.get( '/customer/load' , async (req,resp)=>{
    console.log( req.headers.authorization );
    // 使用 express-jwt 解析 token 后将其中包含的 payload 添加到 req 中
    let { id } = req.user;
    // 根据主键查询用户信息
    let customer = await Customer.findOne( {
        attributes: [ 'id','username', 'nickname' ],
        where: { id }
    } );
    // 若用户存在则向客户端返回用户信息
    if( customer ) {
        resp.json( { success: true , message: '查询成功' , customer } );
        return ;
    }
    // 若指定ID的用户不存在则返回以下提示信息
    resp.json( { success: false , message: '查询失败' } );
});

// 编辑用户信息(目前仅nickname可任意更改，其它字段皆不可)
router.post( '/customer/edit' , (req,resp)=>{
    // 配置 express-jwt 后可以在 express 中间件中通过 user 获取 token 中的用户信息
    const customer = req.user ;
    // 从请求参数中获取用户在界面上填写的昵称
    const nickname = req.body.nickname ;
    // 更新数据 ( update 第一个参数表示被修改的数据，第二个参数表示条件 )
    Customer.update( { nickname } , { where: { id: customer.id } } )
            .then( res => {
                resp.json( { success: true , message: '修改成功' } );
            }).catch( err => {
                resp.json( { success: false , message: '修改失败' } );
            });
});

// 修改登录密码
router.post( '/customer/change' , (req,resp,next)=>{
    let { original , password , confirm } = req.body ;
    // 对 original 、password 、confirm 进行校验
    if( password != confirm ) {
        resp.json({success:false,message:'两次密码不一致'});
        return;
    }
    next();
},async (req,resp)=>{
    let { original, password } = req.body ;
    const c = await Customer.findOne({
                                 attributes:['password','salt'],
                                 where:{
                                     id:req.user.id
                                 }
                             });
    // 根据数据库中的盐值对用户输入的原始密码进行加密                         
    original = encryptor.encrypt( original , c.salt );
    // 若用户输入的原始密码在加盐加密后与数据库中保存的密码不相等
    if( original != c.password ){
        resp.json({success:false,message:'原始密码错误'});
        return ;
    }

    // 重新生成盐值
    let salt = random.salt();
    // 使用新盐值对新密码进行加密
    password = encryptor.encrypt( password , salt );
    // 更新密码 ( update 第一个参数表示被修改数据，第二个参数表示更新条件 )
    Customer.update( {password , salt } , { where: { id: req.user.id } } )
            .then(count=>{
                resp.json({success:true,message:'密码修改成功'});
            }).catch(error=>{
                resp.json({success:false,message:'密码修改失败'});
            });
});

// 注销账号
router.post( '/customer/cancellation' , async (req,resp)=>{
    let { password } = req.body ;
    let { id } = req.user ;
    // 根据主键查询用户信息
    let c = await Customer.findOne({
        attributes:['password','salt'],
        where: { id }
    });
    // 若 c 不存在(即数据库中不存在指定记录)
    if( !c ) {
        resp.json({success:false,message:'账号不存在'});
        return;
    }
    // 对用户输入的密码进行加盐加密处理
    let enc = encryptor.encrypt(password,c.salt);
    // 判断用户输入的密码是否正确
    if( enc != c.password ) {
        resp.json({success:false,message:'密码错误'});
        return;
    }
    // 尝试删除用户
    Customer.destroy({where:{id}})
            .then(result=>{
                resp.json({success:true,message:'账户注销成功'});
            }).catch(error=>{
                console.log( '删除失败: ' , error.name , error.message );
                resp.json({success:false,message:'账户注销失败'});
            });
});

module.exports = router ;